﻿using System;
using Furiant.Figment.Agents;
using Furiant.Figment.Agents.Inventory;

namespace Furiant.Figment.Items.Lootable
{
    /// <summary>
    /// Defines a requirement which must be satisfied in order for the IHasInventory target to
    /// equip or unequip an IEquippable item.
    /// </summary>
    /// <typeparam name="THasInventory">The type of IHasInventory which defines the target to validate the requirement against.</typeparam>
    public class EquipActionCriterion<THasInventory> : IEquipActionCriterion<THasInventory> where THasInventory:IHasInventory
    {
        #region Fields

        private readonly EquipAction _action;
        private readonly Predicate<THasInventory> _criterion;
        private readonly string _feedback;
        
        #endregion

        #region Constructors
        /// <summary>
        /// Defines a requirement which must be satisfied in order for the IHasInventory target to
        /// equip or unequip an IEquippable item.
        /// </summary>
        /// <param name="action">The EquipAction to validate.</param>
        /// <param name="criterion">The function which must return True for the specified target in order for the requirement to be satisfied.</param>
        /// <param name="feedback">The text which describes the criterion to the player.</param>
        public EquipActionCriterion(EquipAction action, Predicate<THasInventory> criterion, string feedback)
        {
            _action = action;
            _criterion = criterion;

            if (string.IsNullOrWhiteSpace(feedback))
            {
                throw new ArgumentException("Value must not be null, empty, or whitespace.", "feedback");
            }

            _feedback = feedback;
        }

        #endregion

        #region Properties

        /// <summary>
        /// The EquipAction to which this requirement is associated.
        /// </summary>
        public EquipAction Action { get { return _action; } }

        /// <summary>
        /// The function which must return True for the specified target in order for the requirement to be satisfied.
        /// </summary>
        public Predicate<THasInventory> Criterion { get { return _criterion; } }

        /// <summary>
        /// The text which describes the Criterion to the player.
        /// </summary>
        public string Feedback { get { return _feedback; } }

        #endregion

        #region Methods

        /// <summary>
        /// Returns whether the Criterion is satisfied by the specified target.
        /// </summary>
        /// <param name="target">The IHasInventory implementor to validate against.</param>
        /// <returns></returns>
        public bool IsSatisfied(THasInventory target)
        {
            if (target.Equals(null))
            {
                throw new ArgumentNullException("target", "The specified target cannot be null.");
            }

            return Criterion(target);
        }

        #endregion
    }
}
